# 数据输入 注意这是从voc格式的转化为yolo3格式的txt文本

# 1.jpg 263,211,324,339,1 165,264,253,372,0 241,194,295,299,2 #3个目标框
# 2.jpg 141,50,400,330,1  # 1个目标框
# 3.jpg 69,172,270,330,2 150,141,229,284,0 285,201,327,331,1 #3个目标框
# 4.jpg 92,72,305,400,1 #1个目标框

# 首先进入get_random_data函数

def get_random_data(annotation_line, input_shape, random=False, max_boxes=20, jitter=.3, hue=.1, sat=1.5, val=1.5, proc_img=True):
    line = annotation_line.split()
    image = Image.open(line[0]) #获取图像位置并读取
    iw, ih = image.size   #(500,375 )
    h, w = input_shape
    box = np.array([np.array(list(map(int,box.split(',')))) for box in line[1:]])

    if not random:
        # resize image
        scale = min(np.float(w)/iw,  np.float(h)/ih) #python 3 scale = min(w/iw,  np.h/ih)
        nw = int(iw*scale)
        nh = int(ih*scale)
        dx = (w-nw)//2
        dy = (h-nh)//2
        image_data=0
        if proc_img:
            image = image.resize((nw,nh), Image.BICUBIC)
            new_image = Image.new('RGB', (w,h), (128,128,128))#生成一个（416,416）灰色图像
            new_image.paste(image, (dx, dy)) #将image 放在灰色图中央。 图像开始的位置坐标会增大哦！
            image_data = np.array(new_image)/255.
        # correct boxes
        box_data = np.zeros((max_boxes,5))
        if len(box)>0:
            np.random.shuffle(box)
            if len(box)>max_boxes: box = box[:max_boxes]
            box[:, [0,2]] = box[:, [0,2]]*scale + dx #dx 为xmin,xmax增量  图像位置变化了 所以 标注信息也要随之变化 这样标注框才不会偏移。
            box[:, [1,3]] = box[:, [1,3]]*scale + dy #dy 为ymin,ymax的增量
            box_data[:len(box)] = box

        return image_data, box_data
    
    # 在经过这个函数过后得到的box_data的维度为[batch_size,max_boxes,5]
    # 而在这个函数里面max_boxes为20 如果这样的话太多了 在这里我把这个调成max_boxes = 4
    # 也就是一张图上最多有4个目标
    # 这里的batch_size我也按照我上面的4张图片将batch_size设置为4
    # 5是xmax,ymax,xmin,ymin,class_id
    # 那这里的box_data的维度为(4,4,5)
    
    # 这里是在没有开启随机读取的状态下 shuffle =False
    # 在这里将其表示出来的话 那么就如下
     box_data = [
                  [[263,211,324,339,1],[165,264,253,372,0],[241,194,295,299,2],[0,0,0,0,0]], # 第一张图片的3个目标框 没有目标的就要填充0
                  [[141,50,400,330,1],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]], # 第二张图片的1个目标框，其余的填0
                  [[69,172,270,330,2],[150,141,229,284,0],[285,201,327,331,1],[100,100,200,200,3]], #第三张图片的4个目标框
                  [[92,72,305,400,1],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]
                ]
    # 是自己手打的这个box_data的话那么他是一个list，没有shape属性
    # box = np.array([np.array(list(map(int,box.split(',')))) for box in line[1:]])
    # 但是这个代码会先将其转换成np.array形式才有shape属性

    # 得到了box_data之后 就进入process_true_boxes函数做y_true了

def preprocess_true_boxes(true_boxes, input_shape, anchors, num_classes):
    assert (true_boxes[..., 4]<num_classes).all(), 'class id must be less than num_classes' #判断类别是否超出了20
    num_layers = len(anchors)//3 # default setting  num_layers=3
    anchor_mask = [[6,7,8], [3,4,5], [0,1,2]] if num_layers==3 else [[3,4,5], [1,2,3]]
    true_boxes = np.array(true_boxes, dtype='float32')
    input_shape = np.array(input_shape, dtype='int32')
    boxes_xy = (true_boxes[..., 0:2] + true_boxes[..., 2:4]) // 2 # 计算中心点坐标  (xmin+xmax)/2  (ymin+ymax)/2
    # print(boxes_xy)
    boxes_wh = true_boxes[..., 2:4] - true_boxes[..., 0:2]#计算图片宽高  xmax-xmin   ymax-ymin
    # print(boxes_wh)
    true_boxes[..., 0:2] = boxes_xy/input_shape[::-1]  #将中心点及宽高 对输入图片416 做归一化
    # print(true_boxes[..., 0:2])
    true_boxes[..., 2:4] = boxes_wh/input_shape[::-1]
    # print(true_boxes[..., 2:4])
    m = true_boxes.shape[0]   #获取barchsize大小 此处m=4
    grid_shapes = [input_shape//{0:32, 1:16, 2:8}[l] for l in range(num_layers)] #获取特征图的尺寸 13， 26,52
    # [array([13, 13], dtype=int32), array([26, 26], dtype=int32), array([52, 52], dtype=int32)]

    y_true = [np.zeros((m,grid_shapes[l][0],grid_shapes[l][1],len(anchor_mask[l]),5+num_classes),
        dtype='float32') for l in range(num_layers)]
    # (4,13,13,3,25) 

    # Expand dim to apply broadcasting.
    anchors = np.expand_dims(anchors, 0)#扩展第一个维度原来为(9,2) --->(1,9,2)这样操作可以充分利用numpy的广播机制
    anchor_maxes = anchors / 2.  #将anchors 中心点放（0,0） 因为anchors没有中心点只有宽高，计算与boxs计算iou时两者中心点均为（0.0）
    anchor_mins = -anchor_maxes # anchor_mins 记录了xim ymin 两个坐标点
    valid_mask = boxes_wh[..., 0]>0  #判断是否有异常标注boxes

    for b in range(m):
        # print(m)
        # Discard zero rows.
        wh = boxes_wh[b, valid_mask[b]]
        # print(wh)
        if len(wh)==0: continue
        # Expand dim to apply broadcasting.                 
        wh = np.expand_dims(wh, -2)
        box_maxes = wh / 2.              
        box_mins = -box_maxes            
        intersect_mins = np.maximum(box_mins, anchor_mins)
        intersect_maxes = np.minimum(box_maxes, anchor_maxes)
        intersect_wh = np.maximum(intersect_maxes - intersect_mins, 0.)
        intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]
        box_area = wh[..., 0] * wh[..., 1]
        anchor_area = anchors[..., 0] * anchors[..., 1]
        iou = intersect_area / (box_area + anchor_area - intersect_area)
        # print(wh)
        # Find best anchor for each true box
        best_anchor = np.argmax(iou, axis=-1)
        print(best_anchor)
        print(best_anchor.shape)
        for t, n in enumerate(best_anchor):
            for l in range(num_layers):
                if n in anchor_mask[l]:
                    i = np.floor(true_boxes[b,t,0]*grid_shapes[l][1]).astype('int32')
                    j = np.floor(true_boxes[b,t,1]*grid_shapes[l][0]).astype('int32')
                    k = anchor_mask[l].index(n)
                    c = true_boxes[b,t, 4].astype('int32')
                    y_true[l][b, j, i, k, 0:4] = true_boxes[b,t, 0:4]
                    print(true_boxes[b,t, 0:4])
                    y_true[l][b, j, i, k, 4] = 1
                    y_true[l][b, j, i, k, 5+c] = 1

    return y_true


# 将代码运行后得到的一些重要的参数在这里写出来
# 首先是读入进去的box_data 在这路process_true_boxes函数中box_data就是trtrue_boxes
# true_boxes = np.array(true_boxes, dtype='float32')
# 变换成np.array的形式
# 如下
'''
 [[[263. 211. 324. 339.   1.]
  [165. 264. 253. 372.   0.]
  [241. 194. 295. 299.   2.]
  [  0.   0.   0.   0.   0.]]

 [[141.  50. 400. 330.   1.]
  [  0.   0.   0.   0.   0.]
  [  0.   0.   0.   0.   0.]
  [  0.   0.   0.   0.   0.]]

 [[ 69. 172. 270. 330.   2.]
  [150. 141. 229. 284.   0.]
  [285. 201. 327. 331.   1.]
  [100. 100. 200. 200.   3.]]

 [[ 92.  72. 305. 400.   1.]
  [  0.   0.   0.   0.   0.]
  [  0.   0.   0.   0.   0.]
  [  0.   0.   0.   0.   0.]]]
  '''


'''
iou
这是第一张图片每个框和9个anchor的iou的值
每个框的9个值用一个[]包括
总共有4个小[] 最后就如下
[[目标框1和9个iou的值],[目标框2和9个iou的值],[....],[....]]

[[0.01664959 0.06147541 0.09720799 0.234375   0.34954794 0.89920594
  0.43031823 0.25278425 0.06421158]
 [0.01367845 0.05050505 0.07986111 0.19255051 0.29356061 0.62759775
  0.65868263 0.30769231 0.07815918]
 [0.02292769 0.08465608 0.13386243 0.32275132 0.40298507 0.80757727
  0.432      0.18356643 0.04662906]]

然后有四个图片 用四个这样的list表示

然后best_anchor的形式为
[5 6 5]
[8]
[7 5 5 6]
[8]
都是一维的
'''
